﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace VGSoftware.AutoExtractService.PlugIn
{
	public class PlugInManager
	{
		private static DirectoryInfo PlugInDirectory = new DirectoryInfo(Properties.Settings.Default.PlugInDirectory);
		private List<IAutoExtractServicePlugIn> _plugIns;
		private Settings _settings;

		private static PlugInManager _instance;
		private static object _instanceLock = new object();

		private PlugInManager()
		{
		}

		#region Properties

		public static PlugInManager Instance
		{
			get
			{
				if (_instance == null)
				{
					lock (_instanceLock)
					{
						if (_instance == null)
						{
							_instance = new PlugInManager();
						}
					}
				}
				return _instance;
			}
		}

		private List<IAutoExtractServicePlugIn> PlugIns
		{
			get
			{
				if (_plugIns == null)
				{
					_plugIns = new List<IAutoExtractServicePlugIn>();
				}
				return _plugIns;
			}
			set
			{
				_plugIns = value;
			}
		}

		private Settings Settings
		{
			get
			{
				if (_settings == null)
				{
					_settings = new Settings();
					_settings.DelayInSeconds = Properties.Settings.Default.DelayInSeconds;
					_settings.FoldersToExclude = new List<string>(Properties.Settings.Default.FoldersToExclude.Cast<string>());
					_settings.FoldersToWatch = new List<string>(Properties.Settings.Default.FoldersToWatch.Cast<string>());
					_settings.PathToExtractTo = Properties.Settings.Default.PathToExtractTo;
					_settings.WinRarPath = Properties.Settings.Default.WinRarPath;
				}
				return _settings;
			}
		}

		#endregion

		#region PlugIn Events

		public bool AfterFilesExtracted(IAutoExtractServiceData data)
		{
			foreach (IAutoExtractServicePlugIn plugIn in PlugIns)
			{
				try
				{
					plugIn.AfterFilesExtracted(Settings, data);
				}
				catch
				{
					return false;
				}
			}
			return true;
		}

		public bool BeforeFilesExtracted(IAutoExtractServiceData data)
		{
			foreach (IAutoExtractServicePlugIn plugIn in PlugIns)
			{
				try
				{
					plugIn.BeforeFilesExtracted(Settings, data);
					if (data.CancelExtraction)
					{
						return false;
					}
				}
				catch
				{
					return false;
				}
			}
			return true;
		}

		#endregion

		#region List/Loading of plugins

		public void Initialize()
		{
			PlugIns.Clear();
			LoadPlugIns();
		}

		private void LoadPlugIns()
		{
			List<Assembly> assemblies = new List<Assembly>();
			foreach (FileInfo file in PlugInDirectory.GetFiles("*.dll"))
			{
				try
				{
					Assembly assembly = Assembly.LoadFrom(file.FullName);
					if (assembly != null)
					{
						assemblies.Add(assembly);
					}
				}
				catch { }
			}
			PlugIns = FindPlugIns(assemblies);
		}

		private List<IAutoExtractServicePlugIn> FindPlugIns(List<Assembly> assemblies)
		{
			List<IAutoExtractServicePlugIn> plugins = new List<IAutoExtractServicePlugIn>(assemblies.Count);
			foreach (Configuration.PlugInConfigurationElement element in Configuration.PlugInConfigurationSection.GetConfig().PlugIns)
			{
				Assembly assembly = assemblies.First<Assembly>(item => item.GetType(element.Type) != null);
				if (assembly != null)
				{
					Type type = assembly.GetType(element.Type);
					IAutoExtractServicePlugIn instance = (IAutoExtractServicePlugIn)Activator.CreateInstance(type);
					plugins.Add(instance);
				}
			}
			return plugins;
		}

		#endregion
	}
}